package com.caishi.lkx.exam.util;


import com.aliyun.oss.OSS;
import com.aliyun.oss.model.PutObjectRequest;
import com.caishi.lkx.exam.QuestionCollectionBlockItem;
import com.caishi.lkx.exam.ienum.type.QuestionDifficulty;
import com.caishi.lkx.exam.ienum.type.QuestionSourceType;
import com.caishi.lkx.exam.ienum.type.QuestionType;
import com.caishi.lkx.exam.model.CategoryModel;
import com.caishi.lkx.exam.model.QuestionModel;
import com.caishi.lkx.exam.model.QuestionTypeModel;
import com.caishi.lkx.exam.service.ICategoryService;
import com.caishi.lkx.exam.service.IQuestionService;
import com.caishi.lkx.exam.service.IQuestionTypeService;
import com.caishi.lkx.exam.util.pojo.Question;
import com.zzw.common.Wrappers;
import com.zzw.common.file.OssPlugins;
import org.apache.poi.xwpf.usermodel.*;
//import org.example.springboot2.enums.QuestionType;
//import org.example.springboot2.pojo.Question;
import org.openxmlformats.schemas.drawingml.x2006.picture.CTPicture;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.*;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class WordToHtmlInOrder {
    @Resource
    private IQuestionTypeService questionTypeService;
    @Resource
    private IQuestionService questionService;
    @Resource
    private ICategoryService categoryService;

    @Autowired
    OssPlugins ossPlugins;
    //    非首位的分隔符匹配(：、:.)
//     "^(.).*([.:\uFF1A\u3001])(.*)$";
    static final String regex = "^(.*?)([。.:\uFF1A\u3001]).*$";
    static final String ANALYSIS = "解析";
    static final String ANSWER = "答案";

    private QuestionType currentType = QuestionType.singleChoice;
    static final QuestionType[] questionTypes = QuestionType.values();
    private static final long now = System.currentTimeMillis();
    private List<Question> questions = new ArrayList<Question>();
    private Question currentQuestion;
    private static final Map<QuestionType, String> questionTypeMap = new HashMap<>();


    static enum ParagraphType {
        TYPE,
        TITLE,
        OPTION,
        ANSWER,
        ANALYSIS
    }

    private static final String questionTypeRegex;
    private static final Map<String, QuestionType> QuestionTypeMap;

    private Matcher currentMatcher;

    static {
        HashMap<String, QuestionType> map = new HashMap<>();
        String reg = "^(";
        for (QuestionType questionType : questionTypes) {
            map.put(questionType.getDesc(), questionType);
            reg += questionType.getDesc() + "|";
        }
        questionTypeRegex = reg.substring(0, reg.length() - 1) + ")";
        QuestionTypeMap = map;
    }

    //    如果包含所有前缀，则去掉前缀即可，如果前缀被拆分，拼接run（run必须是非图片等格式），再拆分，单例bean要不要加个锁synchronized
    public List<Question> parseFileToObject(MultipartFile fin) throws IOException {

        // 加载Word文档
        XWPFDocument document = new XWPFDocument(fin.getInputStream());
//            截取掉前缀，剩余文本图片按顺序富文本化，将富文本保存到对象
        for (XWPFParagraph paragraph : document.getParagraphs()) {
            // 创建HTML文件的开头部分
            StringBuilder htmlContent = new StringBuilder();
            List<XWPFRun> runs = paragraph.getRuns();
//                当前段落类型
            ParagraphType currentParagraphType = null;
            if (runs != null) {
//                    如果最前面的run没有分隔符(.|、|:),且runs.size>1，则删除前面的run，将文本放在后面一个run
                for (int i = 0; i < runs.size(); i++) {

                    XWPFRun run = runs.get(i);
                    // 处理文本
                    String text = run.getText(0);
                    if (text != null && !text.isEmpty()) {
                        if (i == 0) {
                            Pattern compile = Pattern.compile(regex);
                            Matcher matcher = compile.matcher(text);
                            currentMatcher = matcher;

                            if (matcher.matches()) {
//                                    替换截取前缀
                                run.setText(run.getText(0).substring(matcher.group(1).length() + matcher.group(2).length()), 0);
                                String htmlText = parseRun(run);

                                htmlContent.append(htmlText);
//                                    设置对象属性,当前段落类型
                                if (isOptions(text)) {
                                    currentParagraphType = ParagraphType.OPTION;
                                } else if (isAnalysis(text)) {
                                    currentParagraphType = ParagraphType.ANALYSIS;
                                } else if (isAnswer(text)) {
                                    currentParagraphType = ParagraphType.ANSWER;
                                } else if (isTitle(text)) {
                                    currentParagraphType = ParagraphType.TITLE;
                                }

                            } else {
//                                    没匹配上的,要么是题型，要么是多余的行段落
                                if (runs.size() > 1) {
//                                        这里的原因是有的段落前面显示为“1.”,但是这个“.”确是中文的，word上看不出来,poi解析将其拆分了，整个人都不好了
                                    XWPFRun xwpfRun = runs.get(i + 1);
                                    xwpfRun.setText(text + xwpfRun.getText(0), 0);
                                    paragraph.removeRun(i);
                                    i--;
                                    continue;
                                } else {
//                                        判断是不是题型
                                    QuestionType type = getType(text);
                                    if (type != null) {
                                        currentType = type;
                                        currentParagraphType = ParagraphType.TYPE;
                                    }
                                    break;
                                }
                            }
                        } else {
                            String htmlText = parseRun(run);
                            htmlContent.append(htmlText);
                        }
//                            htmlContent.delete()
                    }
                    // 处理图片
                    List<XWPFPicture> pictures = run.getEmbeddedPictures();
                    for (XWPFPicture picture : pictures) {
                        XWPFPictureData pictureData = picture.getPictureData();
                        if (pictureData != null) {
                            String ext = pictureData.suggestFileExtension();
                            OSS client = ossPlugins.createClient();
                            String fileName = "/question/img" + LocalDateTime.now() + ext;
                            ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(pictureData.getData());
                            PutObjectRequest putObjectRequest = new PutObjectRequest(ossPlugins.ossConfig.getBucket(), ossPlugins.getFilePath(fileName), byteArrayInputStream);

                            client.putObject(putObjectRequest);
                            String url = "https://" + ossPlugins.ossConfig.getBucket() + "." + ossPlugins.ossConfig.getEndpoint() + "/" + ossPlugins.getFilePath(fileName);
//                                String base64String = Base64.getEncoder().encodeToString(pictureData.getData());
//                                String mimeType = pictureData.suggestFileExtension();
//                                htmlContent.append("<img src=\"data:" + mimeType + ";base64," + base64String + "\" alt=\"image\" />");



                            CTPicture ctPicture =  picture.getCTPicture();//853440
                            long cx = ctPicture.getSpPr().getXfrm().getExt().getCx();
                            long cy = ctPicture.getSpPr().getXfrm().getExt().getCy();

                             final int dpi = 96;
//                            // 将宽度和高度从 EMU（English Metric Units）转换为像素
                            double width=cx / (914400.0 / dpi);
                            double height=cy / (914400.0 / dpi);

                            htmlContent.append("<img src=\"" + url + "\" alt=\"image\" style=\"width:"+width+"px;height:"+height+"px;\"/>");

                        }
                    }
                }

                if (currentParagraphType == ParagraphType.OPTION) {

                    currentQuestion.getOptions().add(Map.of(currentMatcher.group(1), htmlContent.toString()));


                    Map<String, Object> map = new HashMap<>();
                    map.put("option", currentMatcher.group(1));
                    ArrayList<Map<String, Object>> maps = new ArrayList<>();
                    maps.add(Map.of("vl", htmlContent.toString(), "tp", "html"));
                    map.put("content", maps);
                    currentQuestion.getQuOption().add(map);

                } else if (currentParagraphType == ParagraphType.TITLE) {
                    if (currentQuestion != null) {
                        questions.add(currentQuestion);
                    }
                    currentQuestion = new Question<>();
                    currentQuestion.setTitle(htmlContent.toString());
                    currentQuestion.setQuestionType(currentType);

                    ArrayList<Map<String, String>> strings = new ArrayList<>();
                    HashMap<String, String> stringStringHashMap = new HashMap<>();
                    stringStringHashMap.put("vl", htmlContent.toString());
                    stringStringHashMap.put("tp", "html");
                    strings.add(stringStringHashMap);
                    currentQuestion.setStem(strings);
                } else if (currentParagraphType == ParagraphType.ANSWER) {
                    if (currentType == QuestionType.singleChoice) {
                        currentQuestion.setAnswers(paragraph.getText().trim());
                    } else if (currentType == QuestionType.multipleChoice) {
                        currentQuestion.setAnswers(Arrays.stream(paragraph.getText().trim().split("")).toList());
                    } else if (currentType == QuestionType.indefiniteMultipleChoice) {
                        currentQuestion.setAnswers(Arrays.stream(paragraph.getText().trim().split("")).toList());
                    } else if (currentType == QuestionType.judgment) {
//                            判断题0或1
                        String answer = paragraph.getText().trim();
                        currentQuestion.setAnswers(Integer.valueOf(answer == "对" ? 1 : 0));

                        List<Map<String, Object>> quOption = new ArrayList<Map<String, Object>>();
                        for (int i = 0; i < 2; i++) {
                            HashMap<String, Object> quOptionMap = new HashMap<>();
                            ArrayList<Map<String, Object>> content = new ArrayList<>();
                            HashMap<String, Object> contentMap = new HashMap<>();
                            quOptionMap.put("option", i);
                            contentMap.put("vl", i == 0 ? "错误" : "正确");
                            contentMap.put("tp", "text");
                            content.add(contentMap);
                            quOptionMap.put("content", content);
                            quOption.add(quOptionMap);
                        }
                        currentQuestion.setQuOption(quOption);

                    } else if (currentType == QuestionType.fill) {
                        String[] split = paragraph.getText().trim().split("\\|");
                        List<String> list = Arrays.stream(split).toList();
                        currentQuestion.setAnswers(list);

                        //                    填空题根据答案的长度变化option
                        List<Map<String, Object>> quOption = new ArrayList<Map<String, Object>>();

                        List<HashMap<String, Object>> lists1=list.stream().map(e->{
                            HashMap<String, Object> answerMap = new HashMap<>();
                            answerMap.put("pt", new ArrayList<>());
                            ArrayList<Map<String, Object>> vlList = new ArrayList<>();
                            HashMap<String, Object> vlMap = new HashMap<>();
                            vlMap.put("tp", "text");
                            vlMap.put("vl", e);
                            vlList.add(vlMap);
                            answerMap.put("vl", vlList);

                            HashMap<String, Object> quOptionMap = new HashMap<>();
                            ArrayList<Map<String, Object>> content = new ArrayList<>();
                            HashMap<String, Object> contentMap = new HashMap<>();
                            contentMap.put("tp", "text");
                            content.add(contentMap);
                            quOptionMap.put("content", content);
                            quOption.add(quOptionMap);

                            return answerMap;
                        }).toList();
                        currentQuestion.setAnswers(lists1);
                        currentQuestion.setQuOption(quOption);

                    } else if (currentType == QuestionType.text) {
                        currentQuestion.setAnswers(htmlContent.toString());
                        List<Map<String, Object>> quOption = new ArrayList<Map<String, Object>>();

                        HashMap<String, Object> quOptionMap = new HashMap<>();
                        ArrayList<Map<String, Object>> content = new ArrayList<>();
                        HashMap<String, Object> contentMap = new HashMap<>();
                        contentMap.put("tp", "html");
                        content.add(contentMap);
                        quOptionMap.put("content", content);
                        quOption.add(quOptionMap);
                        currentQuestion.setQuOption(quOption);
                    }
                } else if (currentParagraphType == ParagraphType.ANALYSIS) {
                    currentQuestion.setAnalysis(htmlContent.toString());

                    ArrayList<Map<String, String>> strings = new ArrayList<>();
                    HashMap<String, String> stringStringHashMap = new HashMap<>();
                    stringStringHashMap.put("vl", htmlContent.toString());
                    stringStringHashMap.put("tp", "html");
                    strings.add(stringStringHashMap);
                    currentQuestion.setAnswerDesc(strings);
                }
            }
        }
        questions.add(currentQuestion);
        return questions;
    }

    private String parseRun(XWPFRun run) {
        StringBuilder html = new StringBuilder();

        // 获取文本内容
        String text = run.getText(0);
        if (text == null) {
            text = "";
        }

        // 获取字体样式
        CTRPr rPr = run.getCTR().getRPr();


        if (rPr != null) {
//            org.openxmlformats.schemas.wordprocessingml.x2006.main
            String fontFamily;
            CTOnOff b=rPr.getB();
            CTOnOff i =rPr.getI();
            CTUnderline u = rPr.getU();
            CTHighlight highlight=rPr.getHighlight();
            CTColor color1 =rPr.getColor();
            CTFonts fonts = rPr.getRFonts();
            if (fonts != null) {
                 fontFamily = fonts.getAscii();
                if (fontFamily != null) {
                    html.append("<span style=\"font-family: ").append(fontFamily).append(";\">");
                }
            }

            if (b != null && b.getVal() != null) {
                html.append("<b>");
            }

            if (i != null && i.getVal() != null) {
                html.append("<i>");
            }

            if (u != null && u.getVal() != null) {
                html.append("<u>");
            }


            if (highlight != null) {
                STHighlightColor.Enum highlightColor = highlight.getVal();
                if(highlightColor.intValue()!=17){
                    //                highlightColor.toString();
//            Enum.toString()返回值不是十六进制，而是颜色的英文单词
                    html.append("<span style=\"background-color: ").append(highlightColor).append(";\">");
                }
            }

//            if (color1 != null && !color1.getVal().equals("auto")) {
////                var color1 = rPr.getColor().getVal();
////                返回byte数组
//                String color = bytesToHex((byte[]) rPr.getColor().getVal());
//                html.append("<span style=\"color: #").append(color).append(";\">");
//            }

            // 添加文本内容
            html.append(text);

//            if (color1 != null && !color1.getVal().equals("auto")) {
//                html.append("</span>");
//            }


            if (highlight != null) {
                STHighlightColor.Enum highlightColor = highlight.getVal();
                if(highlightColor.intValue()!=17){
                    html.append("</span>");
                }

            }


            if (u != null && u.getVal() != null) {
                html.append("</u>");
            }

            if (i != null && i.getVal() != null) {
                html.append("</i>");
            }

            if (b != null && b.getVal() != null) {
                html.append("</b>");
            }

            if (fonts != null) {
                fontFamily = fonts.getAscii();
                if (fontFamily != null) {
                    html.append("</span>");
                }
            }
        }else{
            html.append(text);
        }

        return html.toString();
    }

    private static String bytesToHex(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02x", b & 0xff));
        }
        return sb.toString();
    }

    private boolean isOptions(String text) {
//        java.util.regex.Pattern pattern = java.util.regex.Pattern.compile("^(\\d+[.、])\\s.*");
//        java.util.regex.Matcher matcher = pattern.matcher(text);
//        if (matcher.find()) {
//            return matcher.group(1); // 返回捕获的序号部分
//        }
        return text.matches("^[A-Z][、.].*");
    }

    //    正则是不是更耗性能
    private boolean isAnalysis(String text) {
//        return text.matches("^"+ANALYSIS+".*");
        return text.startsWith(ANALYSIS);
    }

    private boolean isAnswer(String text) {
//        return text.matches("^"+ANSWER+".*");
        return text.startsWith(ANSWER);
    }

    private boolean isTitle(String text) {
        if (currentMatcher != null) {
            return currentMatcher.group(1).matches("\\d+");
        }
        return false;
    }

    public static QuestionType getType(String text) {
        Pattern pattern = Pattern.compile(questionTypeRegex);
        Matcher matcher = pattern.matcher(text);
        if (matcher.matches()) {
            return QuestionTypeMap.get(matcher.group(1));
        }
        return null;
    }

    public void reset() {
        currentQuestion = null;
        currentMatcher = null;
        questions = new ArrayList<Question>();
    }
//    上传入库试题方法,返回上传后的试题集合，传入必要的参数（）
    public Map<String, Object> uploadFileToQuestion(MultipartFile file,Map<String,Object> params) throws IOException {
        Long categoryId =(Long) params.get("categoryId");
        Integer knowledgeLevel=(Integer) params.get("knowledgeLevel");

        parseFileToObject(file);
        List<QuestionModel> questionModels = new ArrayList<>(questions.size());
        List<QuestionCollectionBlockItem> contentList = new ArrayList<>();
        Map<QuestionType, List<Question>> questionListMap = new HashMap<>();

        List<QuestionType> list = Arrays.stream(QuestionType.values()).toList();



        if(questionTypeMap.isEmpty()||System.currentTimeMillis()-now>1000*60*60){
            List<QuestionTypeModel> questionTypeModels = questionTypeService.selectList(Wrappers.<QuestionTypeModel>lambdaQuery().in(QuestionTypeModel::getFirstType, list), 50);
            for (QuestionTypeModel questionTypeModel : questionTypeModels) {
                if (questionTypeMap.containsKey(questionTypeModel.getFirstType())) {
                    if (questionTypeModel.getName() == questionTypeModel.getFirstType().getDesc()) {
                        questionTypeMap.replace(questionTypeModel.getFirstType(), questionTypeModel.getId());
                    }
                } else {
                    questionTypeMap.put(questionTypeModel.getFirstType(), questionTypeModel.getId());
                }
            }
        }
//        分类题目
        for (Question question : questions) {
            if (questionListMap.containsKey(question.getQuestionType())) {
                questionListMap.get(question.getQuestionType()).add(question);
            } else {
                ArrayList<Question> lists = new ArrayList<>();
                lists.add(question);
                questionListMap.put(question.getQuestionType(), lists);
            }
        }
//        三重遍历，大题型遍历，小题型遍历，选项遍历
        for (QuestionType questionType : questionListMap.keySet()) {
            QuestionCollectionBlockItem questionCollectionBlockItem = new QuestionCollectionBlockItem();
            List<QuestionCollectionBlockItem.QuestionCollectionItem> qs = new ArrayList<>();
//            小题型遍历
            int num=0;
            for (Question question : questionListMap.get(questionType)) {
                num++;
                QuestionCollectionBlockItem.QuestionCollectionItem questionCollectionItem=new QuestionCollectionBlockItem.QuestionCollectionItem();
                questionCollectionItem.setSort(num);
                questionCollectionItem.setScore(new BigDecimal(1));

                QuestionModel questionModel = new QuestionModel();
                questionModel.setStem(question.getStem());
                questionModel.setStemHigh(question.getStem());
                questionModel.setAnswerDesc(question.getAnswerDesc());



                questionModel.setQuOption(question.getQuOption());
                questionModel.setFirstType(question.getQuestionType());
                questionModel.setAnswer(question.getAnswers());
                questionModel.setScore(new BigDecimal(1));
                questionModel.setDeleted(false);
                questionModel.setCategoryId(categoryId);
//            questionModel.setSign();
//            questionModel.setSourceId();

//            questionModel.setType();

                questionModel.setTypeId(questionTypeMap.get(question.getQuestionType()));
                questionModel.setKnowledgeLevel(knowledgeLevel);
                questionModel.setSort(1);
                questionModel.setDifficulty(QuestionDifficulty.normal);
                questionModel.setSourceType(QuestionSourceType.importHand);
//                String sid = generateUUIDByTimestamp();
//                if (null != entity.getCategoryId()) {
//                    sid = entity.getCategoryId() + "_" + sid;
//                }
//                questionModel.setId(sid);
//                questionCollectionItem.setId(sid);
                questionModel.setIsHide(false);
                if (!questionModel.getFirstType().equals(QuestionType.combination)) {
                    questionModel.setQualityLevel(questionService.additionQualityLevel(questionModel));
                }

                questionModels.add(questionModel);
                qs.add(questionCollectionItem);
            }


            questionCollectionBlockItem.setTyName(questionType.getDesc());
            questionCollectionBlockItem.setSort(1);
            questionCollectionBlockItem.setQs(qs);
            questionCollectionBlockItem.setDesc(questionType.getDesc());
            questionCollectionBlockItem.setScore(new BigDecimal(1));

            contentList.add(questionCollectionBlockItem);

        }
        CategoryModel category = categoryService.getById(categoryId);


//      插入操作执行了重设id。。。  examId.hashCode() & 63 + UUID
        questionService.insertBatch(questionModels, category.getExamId());

        reset();


        List<String> questionIds = new ArrayList<>();
        //        根据id重设content里的qs
        int num=0;
        for(QuestionCollectionBlockItem questionCollectionBlockItem:contentList){
            for(QuestionCollectionBlockItem.QuestionCollectionItem questionCollectionItem:questionCollectionBlockItem.getQs()){
                questionCollectionItem.setId(questionModels.get(num).getId());
                questionIds.add(questionCollectionItem.getId());
                num++;
            }
        }

        Map<String, Object> returnMap = new HashMap<>();
        returnMap.put("category", category);
        returnMap.put("questionModels", questionModels);
        returnMap.put("contentList", contentList);
        returnMap.put("questionIds", questionIds);

        return returnMap;
    }
}
